package cn.harry.modular.portrait.service.impl;

import cn.harry.modular.portrait.domain.User;
import cn.harry.modular.portrait.mapper.UserMapper;
import cn.harry.modular.portrait.service.UserService;
import cn.harry.modular.portrait.vo.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 *
 * @author harry
 * @公众号 Harry技术
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importUser(List<PortraitUserVO> list) {
        List<User> users = BeanUtil.copyToList(list, User.class);
        if (!users.isEmpty()) {
            saveBatch(users);
        }
    }

    @Override
    public List<Long> listUserIdsByCondition(UserSegmentsCondition condition) {
        List<User> list;
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();

//    人口属性： 用户性别(shoppingGender)、活跃度(userActivityLevel)
//    行为属性：近 30 日购买次数(recent30DaysPurchaseCount)、近 30日购买金额(recent30DaysPurchaseAmount)
        List<UserSegmentsCondition.Condition> conditions = condition.getConditions();
        if (conditions != null && !conditions.isEmpty()) {
            for (UserSegmentsCondition.Condition item : conditions) {
                if (item.getField().equals("shoppingGender")) {
                    switch (item.getOperator()) {
                        case ">" -> queryWrapper.gt("shopping_gender", item.getValue());
                        case "=" -> queryWrapper.eq("shopping_gender", item.getValue());
                        case "<" -> queryWrapper.lt("shopping_gender", item.getValue());
                    }
                }
                if (item.getField().equals("userActivityLevel")) {
                    switch (item.getOperator()) {
                        case ">" -> queryWrapper.gt("user_activity_level", item.getValue());
                        case "=" -> queryWrapper.eq("user_activity_level", item.getValue());
                        case "<" -> queryWrapper.lt("user_activity_level", item.getValue());
                    }
                }
                if (item.getField().equals("recent30DaysPurchaseCount")) {
                    switch (item.getOperator()) {
                        case ">" -> queryWrapper.gt("recent30_days_purchase_count", item.getValue());
                        case "=" -> queryWrapper.eq("recent30_days_purchase_count", item.getValue());
                        case "<" -> queryWrapper.lt("recent30_days_purchase_count", item.getValue());
                    }
                }
                if (item.getField().equals("recent30DaysPurchaseAmount")) {
                    switch (item.getOperator()) {
                        case ">" -> queryWrapper.gt("recent30_days_purchase_amount", item.getValue());
                        case "=" -> queryWrapper.eq("recent30_days_purchase_amount", item.getValue());
                        case "<" -> queryWrapper.lt("recent30_days_purchase_amount", item.getValue());
                    }
                }
            }
        }
        list = list(queryWrapper);
        if (!list.isEmpty()) {
            return list.stream().map(User::getId).toList();
        }
        return List.of();
    }

    @Override
    public PopulationAttributeIndicatorsVO populationAttributeIndicators() {
        int shoppingGenderM = 0;
        int shoppingGenderF = 0;
        int recent30DaysNewUser = 0;
        int yesterdayPurchaseUser = 0;

        List<User> list = list();
        // 获取最近一个月注册的用户数
        for (User item : list) {
            if (DateUtil.betweenDay(DateUtil.parse(item.getRegistrationDate()), DateUtil.date(), false) <= 30) {
                recent30DaysNewUser++;
            }
        }
        PopulationAttributeIndicatorsVO vo = new PopulationAttributeIndicatorsVO();
        if (!list.isEmpty()) {
            shoppingGenderM = list.stream().filter(item -> item.getShoppingGender().equals("男")).toList().size();
            shoppingGenderF = list.stream().filter(item -> item.getShoppingGender().equals("女")).toList().size();
            yesterdayPurchaseUser = list.stream().filter(item -> item.getDaysSinceLastOrder() == 1).toList().size(); // 条件待完善
        }
        vo.setShoppingGenderM(shoppingGenderM);
        vo.setShoppingGenderF(shoppingGenderF);
        vo.setRecent30DaysNewUser(recent30DaysNewUser);
        vo.setYesterdayPurchaseUser(yesterdayPurchaseUser);
        return vo;
    }

    @Override
    public List<RfmUserVO> rfmUser() {
        List<User> list = list();
        if (list.isEmpty()) {
            return List.of();
        }
        int count = list.size();
        // 根据 rfm 分组
        Map<String, List<User>> map = list.stream()
                .filter(item -> item.getRfm() != null)
                .collect(Collectors.groupingBy(User::getRfm));
        return map.entrySet().stream().map(item -> {
            RfmUserVO vo = new RfmUserVO();
            vo.setName(item.getKey());
            double val = item.getValue().size() * 100D / count;
            // 保留小数点后两位
            val = Math.round(val * 100) / 100D;
            vo.setCount(val);
            return vo;
        }).toList();
    }

    @Override
    public EchartsOptionVO registeredUserCount() {
        EchartsOptionVO vo = new EchartsOptionVO();
        // 获取最近七天
        JSONArray xData = new JSONArray();
        // 获取最近7天的日期
        List<String> days = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            String day = DateUtil.formatDate(DateUtil.offsetDay(DateUtil.date(), -(6 - i)));
            xData.put(day);
            days.add(day);
        }
        vo.setXData(xData);

        JSONArray yData = new JSONArray();
        days.forEach(day -> {
                    List<User> list = list(new QueryWrapper<User>().lambda().apply("date(registration_date) = {0}", day));
                    if (!list.isEmpty()) {
                        yData.put(list.size());
                    } else {
                        yData.put(0);
                    }
                }
        );

        vo.setYData(yData);
        return vo;

    }

    @Override
    public EchartsOptionVO activeUserCount() {
        EchartsOptionVO vo = new EchartsOptionVO();
        List<User> list = list();
        if (!list.isEmpty()) {
// 根据 user_activity_level 分组
            Map<String, List<User>> map = list.stream()
                    .filter(item -> item.getUserActivityLevel() != null)
                    .collect(Collectors.groupingBy(User::getUserActivityLevel));

            JSONArray yData = new JSONArray();
            JSONArray xData = new JSONArray();
            for (Map.Entry<String, List<User>> entry : map.entrySet()) {
                String key = entry.getKey();
                List<User> value = entry.getValue();
                xData.put(key);
                yData.put(value.size());
            }
            vo.setYData(yData);
            vo.setXData(xData);
        }
        return vo;
    }

    @Override
    public EchartsOptionVO recent30DaysVisitDays() {
        EchartsOptionVO vo = new EchartsOptionVO();
        List<User> list = list();
        if (!list.isEmpty()) {
//            根据recent30DaysActiveDays 分组
            Map<Integer, List<User>> map = list.stream()
                    .filter(item -> item.getRecent30DaysActiveDays() != null)
                    .collect(Collectors.groupingBy(User::getRecent30DaysActiveDays));
            JSONArray yData = new JSONArray();
            JSONArray xData = new JSONArray();
            // 根据 map key排序
            List<Integer> keys = map.keySet().stream().sorted().toList();
            for (Integer key : keys) {
                xData.put(key);
                yData.put(map.get(key).size());
            }
            vo.setYData(yData);
            vo.setXData(xData);
        }
        return vo;
    }

}
